#include <stdio.h>
#include "esp_log.h"
#include "esp_check.h"
#include "sdkconfig.h"
#include "driver/i2c_master.h"
#include "driver/i2s_tdm.h"
#include "es7210.h"

#define TAG "es7210"
#define ES7210_I2C_ADDR (0x41)

/* I2S configurations */
#define I2S_TDM_FORMAT (ES7210_I2S_FMT_I2S)
#define I2S_CHAN_NUM (2)
#define I2S_SAMPLE_RATE (48000)
#define I2S_MCLK_MULTIPLE (I2S_MCLK_MULTIPLE_256)
#define I2S_SAMPLE_BITS (I2S_DATA_BIT_WIDTH_16BIT)
#define I2S_TDM_SLOT_MASK (I2S_TDM_SLOT0 | I2S_TDM_SLOT1)

i2c_master_dev_handle_t es7210_i2c_handle;

static i2s_chan_handle_t es7210_i2s_init(void)
{
    i2s_chan_handle_t i2s_rx_chan = NULL; // 定义接收通道句柄
    ESP_LOGI(TAG, "Create I2S receive channel");
    i2s_chan_config_t i2s_rx_conf = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); // 配置接收通道
    ESP_ERROR_CHECK(i2s_new_channel(&i2s_rx_conf, NULL, &i2s_rx_chan));                        // 创建i2s通道

    ESP_LOGI(TAG, "Configure I2S receive channel to TDM mode");
    // 定义接收通道为I2S TDM模式 并配置
    i2s_tdm_config_t i2s_tdm_rx_conf = {
        .slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_SAMPLE_BITS, I2S_SLOT_MODE_STEREO, I2S_TDM_SLOT_MASK),
        .clk_cfg = {
            .clk_src = I2S_CLK_SRC_DEFAULT,
            .sample_rate_hz = I2S_SAMPLE_RATE,
            .mclk_multiple = I2S_MCLK_MULTIPLE},
        .gpio_cfg = {.mclk = CONFIG_I2S_MCK_PIN, .bclk = CONFIG_I2S_BCK_PIN, .ws = CONFIG_I2S_WS_PIN,
                     .dout = -1, // ES7210 only has ADC capability
                     .din = CONFIG_I2S_DI_PIN},
    };

    ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(i2s_rx_chan, &i2s_tdm_rx_conf)); // 初始化I2S通道为TDM模式

    return i2s_rx_chan;
}

static void es7210_codec_init(void)
{
    // 初始化I2C接口
    int ret = ESP_OK;
    i2c_master_bus_handle_t i2c_handle;
    i2c_master_get_bus_handle(CONFIG_I2C_PORT, &i2c_handle);
    // config i2c port
    ret = i2c_master_probe(i2c_handle, ES7210_I2C_ADDR, 50);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "no find ES7210, address:0x%02X", ES7210_I2C_ADDR);
        return;
    }
    i2c_device_config_t i2c_dev_conf = {
        .scl_speed_hz = CONFIG_I2C_SPEED_KHZ * 1000,
        .device_address = ES7210_I2C_ADDR,
    };
    if (i2c_master_bus_add_device(i2c_handle, &i2c_dev_conf, &es7210_i2c_handle) != ESP_OK)
    {
        ESP_LOGE(TAG, "mount ES7210 fail");
        return;
    }
    ESP_LOGI(TAG, "mount ES7210 success");

    // 配置es7210器件句柄
    es7210_dev_handle_t es7210_handle = NULL;
    es7210_i2c_config_t es7210_i2c_conf = {
        .i2c_port = CONFIG_I2C_PORT,
        .i2c_addr = ES7210_I2C_ADDR};
    ESP_ERROR_CHECK(es7210_new_codec(&es7210_i2c_conf, &es7210_handle));

    // 初始化es7210芯片
    ESP_LOGI(TAG, "Configure ES7210 codec parameters");
    es7210_codec_config_t codec_conf = {
        .i2s_format = I2S_TDM_FORMAT,
        .mclk_ratio = I2S_MCLK_MULTIPLE,
        .sample_rate_hz = I2S_SAMPLE_RATE,
        .bit_width = (es7210_i2s_bits_t)I2S_SAMPLE_BITS,
        .mic_bias = ES7210_MIC_BIAS_2V18,
        .mic_gain = ES7210_MIC_GAIN_18DB,
        .flags.tdm_enable = true};
    ESP_ERROR_CHECK(es7210_config_codec(es7210_handle, &codec_conf));
    ESP_ERROR_CHECK(es7210_config_volume(es7210_handle, 0));
}
#define RECORD_TIME_SEC 10
#define RECORD_FILE_PATH "record.wav"
#define SD_MOUNT_POINT "/sdcard/"
static esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan)
{
    ESP_RETURN_ON_FALSE(i2s_rx_chan, ESP_FAIL, TAG, "invalid i2s channel handle pointer");
    esp_err_t ret = ESP_OK;

    uint32_t byte_rate = I2S_SAMPLE_RATE * I2S_CHAN_NUM * I2S_SAMPLE_BITS / 8;
    uint32_t wav_size = byte_rate * RECORD_TIME_SEC;

    const wav_header_t wav_header = WAV_HEADER_PCM_DEFAULT(wav_size, I2S_SAMPLE_BITS, I2S_SAMPLE_RATE, I2S_CHAN_NUM);

    ESP_LOGI(TAG, "Opening file %s", RECORD_FILE_PATH);
    FILE *f = fopen(SD_MOUNT_POINT RECORD_FILE_PATH, "w");
    ESP_RETURN_ON_FALSE(f, ESP_FAIL, TAG, "error while opening wav file");

    /* Write wav header */
    ESP_GOTO_ON_FALSE(fwrite(&wav_header, sizeof(wav_header_t), 1, f), ESP_FAIL, err,
                      TAG, "error while writing wav header");

    /* Start recording */
    size_t wav_written = 0;
    static int16_t i2s_readraw_buff[4096];
    ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_rx_chan), err, TAG, "error while starting i2s rx channel");
    while (wav_written < wav_size)
    {
        if (wav_written % byte_rate < sizeof(i2s_readraw_buff))
        {
            ESP_LOGI(TAG, "Recording: %" PRIu32 "/%ds", wav_written / byte_rate + 1, RECORD_TIME_SEC);
        }
        size_t bytes_read = 0;
        /* Read RAW samples from ES7210 */
        ESP_GOTO_ON_ERROR(i2s_channel_read(i2s_rx_chan, i2s_readraw_buff, sizeof(i2s_readraw_buff), &bytes_read,
                                           pdMS_TO_TICKS(1000)),
                          err, TAG, "error while reading samples from i2s");
        /* Write the samples to the WAV file */
        ESP_GOTO_ON_FALSE(fwrite(i2s_readraw_buff, bytes_read, 1, f), ESP_FAIL, err,
                          TAG, "error while writing samples to wav file");
        wav_written += bytes_read;
    }

err:
    i2s_channel_disable(i2s_rx_chan);
    ESP_LOGI(TAG, "Recording done! Flushing file buffer");
    fclose(f);

    return ret;
}
